package awesome.cpu.structure;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import awesome.cpu.control.Clock;
import awesome.cpu.gui.GUIOutput;
import awesome.cpu.utils.Mode;

public class BusMonitor {
	
	private final static BusMonitor mInstance = new BusMonitor();
	
	private boolean isRunning = false;
	
	private boolean verbose = false;
	
	private static boolean outputDebug = false;
	
	private static Set<OutputRecord> outputSet;
	private static int cycle;
	
	final static ArrayList<String> componentOrder;	
	static {
		componentOrder = new ArrayList<String>();
		componentOrder.add("Control");
		componentOrder.add("PC");
		componentOrder.add("PCRegister");
		componentOrder.add("MuxPC2M");
		componentOrder.add("Memory");
		componentOrder.add("MemoryRegister");
		componentOrder.add("InstructionRegister");
		componentOrder.add("Mux2WR1");
		componentOrder.add("Mux2WD1");
		componentOrder.add("MuxImm2Ex");
		componentOrder.add("ImmShifter");
		componentOrder.add("RegisterFile");
		componentOrder.add("RegisterA");
		componentOrder.add("RegisterB");
		componentOrder.add("RegisterC");
		componentOrder.add("RegBShifer");
		componentOrder.add("MuxA");
		componentOrder.add("MuxB");
		componentOrder.add("ALU");
		componentOrder.add("FlagRegister");
		componentOrder.add("ALUOut");
		componentOrder.add("Mux2PC");
		componentOrder.add("BranchCondGates");
		componentOrder.add("OrGate");
		
		outputSet = new HashSet<OutputRecord>();
	}
	
	private BusMonitor() {}
	
	public static BusMonitor getInstance() {
		return mInstance;
	}
	
	public static boolean transferData(Component cfrom, int ifrom, Component cto, int ito) {
		int data = cfrom.getData(ifrom);
		boolean flag = cto.setData(ito, data);
		
		if (!flag && Mode.getDebugLevel() >= Mode.DEBUG_LEVEL_PRINT_ERR) {
			System.err.println(cfrom.getClass().getName() + "=>" 
					+ cto.getClass().getName() + " " + flag);		
		}
		
		return flag;
	}
	
	public void start() {
		isRunning = true;
		new Thread() {
			@Override
			public void run() {
				while (isRunning) {
					synchronized (Clock.getInstance()) {
						try {
							Clock.getInstance().wait();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					if (!isRunning) break;
					onClockTick();
				}
			}
		}.start();
	}
	
	public void stop() {
		isRunning = false;
	}
	
	private void onClockTick() {

		if (outputDebug && Mode.getDebugLevel() >= Mode.DEBUG_LEVEL_PRINT_ALL) {
			System.out.println("BusMonitor: IR.op => Control.op data = "
					+InstructionRegister.getInstance()
					.getData(InstructionRegister.KEY_INSTRUCTION_31_24));
		}
		transferData(InstructionRegister.getInstance(),
				InstructionRegister.KEY_INSTRUCTION_31_24,
				Control.getInstance(), Control.KEY_OPERATION);
		transferData(InstructionRegister.getInstance(),
				InstructionRegister.KEY_INSTRUCTION_8_5,
				Control.getInstance(), Control.KEY_FUNCTION);
		
		Control.getInstance().setControl();		
		
		//=========================到达时序部件==========================
		
		// out from Control
		transferData(Control.getInstance(), Control.KEY_IR_WRITE,
				InstructionRegister.getInstance(), InstructionRegister.KEY_IRWRITE_ENABLE);
		transferData(Control.getInstance(), Control.KEY_FLAG_WRITE,
				FlagRegister.getInstance(), FlagRegister.KEY_FLAG_WRITE);
		transferData(Control.getInstance(), Control.KEY_REG_WRITE,
				RegisterFile.getInstance(), RegisterFile.KEY_WRITE_ENABLE);
		transferData(Control.getInstance(), Control.KEY_PCREG_WRITE,
				PCRegister.getInstance(), PCRegister.KEY_PCREG_WRITE);
		
		transferData(Control.getInstance(), Control.KEY_ALU_OP,
				ALU.getInstance(), ALU.KEY_CONTROL_INPUT);
				
		// out from PC
		transferData(PC.getInstance(), PC.KEY_PC_OUT, PCRegister.getInstance(), PCRegister.KEY_PCREG_IN);
		
		// out from IR
		transferData(InstructionRegister.getInstance(), 
				InstructionRegister.KEY_INSTRUCTION_13_9,
				RegisterFile.getInstance(), RegisterFile.KEY_WRITE_REG2);
		
		// out from ALU
		transferData(ALU.getInstance(), ALU.KEY_ALU_RESULT_31_0, ALUOut.getInstance(), ALUOut.KEY_ALU_RESULT_LO);
		transferData(ALU.getInstance(), ALU.KEY_ALU_RESULT_63_32, ALUOut.getInstance(), ALUOut.KEY_ALU_RESULT_HI);
		transferData(ALU.getInstance(), ALU.KEY_N, FlagRegister.getInstance(), FlagRegister.KEY_N);
		transferData(ALU.getInstance(), ALU.KEY_Z, FlagRegister.getInstance(), FlagRegister.KEY_Z);
		transferData(ALU.getInstance(), ALU.KEY_C, FlagRegister.getInstance(), FlagRegister.KEY_C);
		transferData(ALU.getInstance(), ALU.KEY_V, FlagRegister.getInstance(), FlagRegister.KEY_V);
		
		// out from ALUOut
		if (Mode.getDebugLevel() >= Mode.DEBUG_LEVEL_PRINT_ALL) {
			System.out.println("BusMonitor: ALUOut = "+ALUOut.getInstance().getData(ALUOut.KEY_ALU_OUT_LO));
		}
		transferData(ALUOut.getInstance(), ALUOut.KEY_ALU_OUT_HI, RegisterFile.getInstance(), RegisterFile.KEY_WRITE_DATA2);

				
		//=========================非时序============================

		// out from MuxA
		transferData(MuxA.getInstance(), MuxA.KEY_SELECTED, ALU.getInstance(), ALU.KEY_INPUT1);
		transferData(MuxA.getInstance(), MuxA.KEY_SELECTED, 
				ALU.getInstance(), ALU.KEY_INPUT1);
		
		// out from MuxB
		transferData(MuxB.getInstance(), MuxB.KEY_SELECTED, ALU.getInstance(), ALU.KEY_INPUT2);
		transferData(MuxB.getInstance(), MuxB.KEY_SELECTED, 
				ALU.getInstance(), ALU.KEY_INPUT2);
		
		// out from Memory
		transferData(Memory.getInstance(), Memory.KEY_READ_DATA, InstructionRegister.getInstance(), InstructionRegister.KEY_INSTRUCTION_INPUT);
		transferData(Memory.getInstance(), Memory.KEY_READ_DATA, MemoryRegister.getInstance(), MemoryRegister.KEY_MEM_DATA);
		
		// out from OrGate
		transferData(OrGate.getInstance(), OrGate.KEY_RESULT, PC.getInstance(), PC.KEY_PC_WRITE_ENABLE);
		
		// out from RegisterFile
		transferData(RegisterFile.getInstance(), RegisterFile.KEY_READ_DATA1, RegisterA.getInstance(), RegisterA.KEY_REGA_IN);
		transferData(RegisterFile.getInstance(), RegisterFile.KEY_READ_DATA2, RegisterB.getInstance(), RegisterB.KEY_REGB_IN);
		transferData(RegisterFile.getInstance(), RegisterFile.KEY_READ_DATA3, RegisterC.getInstance(), RegisterC.KEY_REGC_IN);
		
		// out from Mux2PC
		transferData(Mux2PC.getInstance(), Mux2PC.KEY_SELECTED, PC.getInstance(), PC.KEY_PC_IN);

		// out from Mux2WR1
		transferData(Mux2WR1.getInstance(), Mux2WR1.KEY_SELECTED, RegisterFile.getInstance(), RegisterFile.KEY_WRITE_REG1);
		
		// out from Mux2WD1
		transferData(Mux2WD1.getInstance(), Mux2WD1.KEY_SELECTED, RegisterFile.getInstance(), RegisterFile.KEY_WRITE_DATA1);
		
		// out from PCRegister
		transferData(PCRegister.getInstance(), PCRegister.KEY_PCREG_OUT, Mux2WD1.getInstance(), Mux2WD1.KEY_PCREG);

		showDataPath(Control.getInstance().getSignals());
		
		synchronized (this) {
			notifyAll();
		}
	}
	
	void showDataPath(ArrayList<Integer> signals){
		
		outputSet.clear();
		if (Control.getInstance().getCurrentStatus() == 0)
			cycle = 1;
		else cycle++;
		if (verbose) GUIOutput.println(" === 第" + cycle + "周期 ===");
		
		
		//第二周期开始时IR将operation和function传给Control，并且读3个寄存器的值
		if (Control.getInstance().getCurrentStatus() == 1){
			showRoute(InstructionRegister.getInstance(), InstructionRegister.KEY_INSTRUCTION_31_24,
					Control.getInstance(), Control.KEY_OPERATION);
			showRoute(InstructionRegister.getInstance(), InstructionRegister.KEY_INSTRUCTION_8_5,
					Control.getInstance(), Control.KEY_FUNCTION);
			showRoute(InstructionRegister.getInstance(), InstructionRegister.KEY_INSTRUCTION_23_19,
					RegisterFile.getInstance(), RegisterFile.KEY_READ_REG1);
			showRoute(InstructionRegister.getInstance(), InstructionRegister.KEY_INSTRUCTION_4_0,
					RegisterFile.getInstance(), RegisterFile.KEY_READ_REG2);
			showRoute(InstructionRegister.getInstance(), InstructionRegister.KEY_INSTRUCTION_18_14,
					RegisterFile.getInstance(), RegisterFile.KEY_READ_REG3);
			showRoute(RegisterFile.getInstance(), RegisterFile.KEY_READ_DATA1,
					RegisterA.getInstance(), RegisterA.KEY_REGA_IN);
			showRoute(RegisterFile.getInstance(), RegisterFile.KEY_READ_DATA2,
					RegisterB.getInstance(), RegisterB.KEY_REGB_IN);
			showRoute(RegisterFile.getInstance(), RegisterFile.KEY_READ_DATA3,
					RegisterC.getInstance(), RegisterC.KEY_REGC_IN);
		}
		
		//PCWriteCondition 被触发
		if (signals.get(Control.KEY_PC_WRITE_CONDITION) != 14){
			showRoute(Control.getInstance(), Control.KEY_PC_WRITE_CONDITION, 
					BranchCondGates.getInstance(), BranchCondGates.KEY_PCWRITE_COND);
			showRoute(FlagRegister.getInstance(), FlagRegister.KEY_FLAG_ALL,
					BranchCondGates.getInstance(), BranchCondGates.KEY_FLAG);
			showRoute(BranchCondGates.getInstance(), BranchCondGates.KEY_RESULT,
					OrGate.getInstance(), OrGate.KEY_CONDITION_MET);
		}
		
		//PCWrite被触发
		if (signals.get(Control.KEY_PC_WRITE) == 1){
			showRoute(Control.getInstance(), Control.KEY_PC_WRITE,
					OrGate.getInstance(), OrGate.KEY_PCWRITE);
			showRoute(OrGate.getInstance(), OrGate.KEY_RESULT,
					PC.getInstance(), PC.KEY_PC_WRITE_ENABLE);
			if (verbose)
				GUIOutput.println("Control : PCWrite !");
		}
		
		//FlagWrite被触发
		if (signals.get(Control.KEY_FLAG_WRITE) != 0){
			showRoute(Control.getInstance(), Control.KEY_FLAG_WRITE,
					FlagRegister.getInstance(), FlagRegister.KEY_FLAG_WRITE);			
			showRoute(ALU.getInstance(), ALU.KEY_N,
					FlagRegister.getInstance(), FlagRegister.KEY_N);
			showRoute(ALU.getInstance(), ALU.KEY_Z, 
					FlagRegister.getInstance(), FlagRegister.KEY_Z);
			showRoute(ALU.getInstance(), ALU.KEY_C, 
					FlagRegister.getInstance(), FlagRegister.KEY_C);
			showRoute(ALU.getInstance(), ALU.KEY_V, 
					FlagRegister.getInstance(), FlagRegister.KEY_V);
			if (verbose) GUIOutput.println("Control : FlagWrite !");
		}
		
		//IorD被触发
		switch (signals.get(Control.KEY_I_OR_D)){	
		case 0:
			showRoute(Control.getInstance(), Control.KEY_I_OR_D,
					MuxPC2M.getInstance(), MuxPC2M.KEY_IORD);
			showRoute(PC.getInstance(), PC.KEY_PC_OUT, 
					MuxPC2M.getInstance(), MuxPC2M.KEY_PC);
			showRoute(MuxPC2M.getInstance(), MuxPC2M.KEY_SELECTED,
					Memory.getInstance(), Memory.KEY_MEM_ADDR);
			if (verbose) GUIOutput.println("Control : IorD = 0 (I)");
			break;		
		case 1:
			showRoute(Control.getInstance(), Control.KEY_I_OR_D,
					MuxPC2M.getInstance(), MuxPC2M.KEY_IORD);
			showRoute(MuxPC2M.getInstance(), MuxPC2M.KEY_SELECTED,
					Memory.getInstance(), Memory.KEY_MEM_ADDR);
			showRoute(ALUOut.getInstance(), ALUOut.KEY_ALU_OUT_LO,
					MuxPC2M.getInstance(), MuxPC2M.KEY_ALUOUT);
			if (verbose) GUIOutput.println("Control : IorD = 0 (D)");
			break;		
		}
		
		//Memory读被触发
		if (signals.get(Control.KEY_MEM_READ) != 0){
			showRoute(Control.getInstance(), Control.KEY_MEM_READ,
					Memory.getInstance(), Memory.KEY_MEM_READ);
			showRoute(MuxPC2M.getInstance(), MuxPC2M.KEY_SELECTED,
					Memory.getInstance(), Memory.KEY_MEM_ADDR);
			if (verbose) GUIOutput.println("Control : MemRead !");
			if (Control.getInstance().getCurrentStatus() == 0)
				showRoute(Memory.getInstance(), Memory.KEY_READ_DATA,
						InstructionRegister.getInstance(), InstructionRegister.KEY_INSTRUCTION_INPUT);
			else
				showRoute(Memory.getInstance(), Memory.KEY_READ_DATA,
						MemoryRegister.getInstance(), MemoryRegister.KEY_MEM_DATA);			
		}
		
		//Memory写被触发
		if (signals.get(Control.KEY_MEM_WRITE) != 0){
			showRoute(Control.getInstance(), Control.KEY_MEM_WRITE,
					Memory.getInstance(), Memory.KEY_MEM_WRITE);
			showRoute(MuxPC2M.getInstance(), MuxPC2M.KEY_SELECTED,
					Memory.getInstance(), Memory.KEY_MEM_ADDR);
			showRoute(RegisterC.getInstance(), RegisterC.KEY_REGC_OUT,
					Memory.getInstance(), Memory.KEY_WRITE_DATA);
			if (verbose) GUIOutput.println("Control : MemWrite !");
		}
		
		//MemToReg被触发
		switch (signals.get(Control.KEY_MEM_TO_REG)){
		case 0:
			showRoute(Control.getInstance(), Control.KEY_MEM_TO_REG,
					Mux2WD1.getInstance(), Mux2WD1.KEY_MEMTOREG);
			showRoute(ALUOut.getInstance(), ALUOut.KEY_ALU_OUT_LO,
					Mux2WD1.getInstance(), Mux2WD1.KEY_ALUOUT);
			showRoute(Mux2WD1.getInstance(), Mux2WD1.KEY_SELECTED,
					RegisterFile.getInstance(), RegisterFile.KEY_WRITE_DATA1);
			if (verbose) GUIOutput.println("Control : MemToReg = 0 (ALUOut)");
			break;
		case 1:
			showRoute(Control.getInstance(), Control.KEY_MEM_TO_REG,
					Mux2WD1.getInstance(), Mux2WD1.KEY_MEMTOREG);
			showRoute(MemoryRegister.getInstance(), MemoryRegister.KEY_MEM_REG,
					Mux2WD1.getInstance(), Mux2WD1.KEY_MR);
			showRoute(Mux2WD1.getInstance(), Mux2WD1.KEY_SELECTED,
					RegisterFile.getInstance(), RegisterFile.KEY_WRITE_DATA1);
			if (verbose) GUIOutput.println("Control : MemToReg = 1 (MR)");
			break;
		case 2:
			showRoute(Control.getInstance(), Control.KEY_MEM_TO_REG,
					Mux2WD1.getInstance(), Mux2WD1.KEY_MEMTOREG);
			showRoute(PC.getInstance(), PC.KEY_PC_OUT,
					Mux2WD1.getInstance(), Mux2WD1.KEY_PC);
			showRoute(Mux2WD1.getInstance(), Mux2WD1.KEY_SELECTED,
					RegisterFile.getInstance(), RegisterFile.KEY_WRITE_DATA1);
			if (verbose) GUIOutput.println("Control : MemToReg = 2 (PC)");
			break;
		case 3:
			showRoute(Control.getInstance(), Control.KEY_MEM_TO_REG,
					Mux2WD1.getInstance(), Mux2WD1.KEY_MEMTOREG);
			showRoute(MuxB.getInstance(), MuxB.KEY_SELECTED,
					Mux2WD1.getInstance(), Mux2WD1.KEY_MOV_SRC);
			showRoute(Mux2WD1.getInstance(), Mux2WD1.KEY_SELECTED,
					RegisterFile.getInstance(), RegisterFile.KEY_WRITE_DATA1);
			if (verbose) GUIOutput.println("Control : MemToReg = 3 (MuxB)");
			break;
		case 4:
			showRoute(Control.getInstance(), Control.KEY_MEM_TO_REG,
					Mux2WD1.getInstance(), Mux2WD1.KEY_MEMTOREG);
			showRoute(PCRegister.getInstance(), PCRegister.KEY_PCREG_OUT,
					Mux2WD1.getInstance(), Mux2WD1.KEY_PCREG);
			showRoute(Mux2WD1.getInstance(), Mux2WD1.KEY_SELECTED,
					RegisterFile.getInstance(), RegisterFile.KEY_WRITE_DATA1);
			if (verbose) GUIOutput.println("Control : MemToReg = 4 (PCReg)");
			break;			
		}
		
		//IRwrite被触发
		if (signals.get(Control.KEY_IR_WRITE) !=0){
			showRoute(Control.getInstance(), Control.KEY_IR_WRITE,
					InstructionRegister.getInstance(), InstructionRegister.KEY_IRWRITE_ENABLE);
			showRoute(Memory.getInstance(), Memory.KEY_READ_DATA,
					InstructionRegister.getInstance(), InstructionRegister.KEY_INSTRUCTION_INPUT);
			if (verbose) GUIOutput.println("Control : IRWrite !");
		}
		
		//PCSource被触发
		switch(signals.get(Control.KEY_PC_SOURCE)){
		case 0:
			showRoute(Control.getInstance(), Control.KEY_PC_SOURCE,
					Mux2PC.getInstance(), Mux2PC.KEY_PC_SRC);
			showRoute(ALU.getInstance(), ALU.KEY_ALU_RESULT_31_0,
					Mux2PC.getInstance(), Mux2PC.KEY_PC_NEXT);
			showRoute(Mux2PC.getInstance(), Mux2PC.KEY_SELECTED,
					PC.getInstance(), PC.KEY_PC_IN);
			if (verbose) GUIOutput.println("Control : PCSrc = 0 (PC+4)");
			break;
		case 1:
			showRoute(Control.getInstance(), Control.KEY_PC_SOURCE,
					Mux2PC.getInstance(), Mux2PC.KEY_PC_SRC);
			showRoute(ALUOut.getInstance(), ALUOut.KEY_ALU_OUT_LO,
					Mux2PC.getInstance(), Mux2PC.KEY_PC_BRANCH);
			showRoute(Mux2PC.getInstance(), Mux2PC.KEY_SELECTED,
					PC.getInstance(), PC.KEY_PC_IN);
			if (verbose) GUIOutput.println("Control : PCSrc = 1 (BranchAddr)");
			break;
		case 2:
			showRoute(Control.getInstance(), Control.KEY_PC_SOURCE,
					Mux2PC.getInstance(), Mux2PC.KEY_PC_SRC);
			showRoute(RegBShifter.getInstance(), RegBShifter.KEY_RESULT,
					Mux2PC.getInstance(), Mux2PC.KEY_PC_JUMP);
			showRoute(Mux2PC.getInstance(), Mux2PC.KEY_SELECTED,
					PC.getInstance(), PC.KEY_PC_IN);
			if (verbose) GUIOutput.println("Control : PCSrc = 2 (JumpAddr)");
			break;
		}
		
		//ALU被激活
		if (signals.get(Control.KEY_ALU_OP) != -1){
			showRoute(Control.getInstance(), Control.KEY_ALU_OP,
					ALU.getInstance(), ALU.KEY_CONTROL_INPUT);
			showRoute(MuxA.getInstance(), MuxA.KEY_SELECTED,
					ALU.getInstance(), ALU.KEY_INPUT1);
			showRoute(MuxB.getInstance(), MuxB.KEY_SELECTED,
					ALU.getInstance(), ALU.KEY_INPUT2);
			showRoute(ALU.getInstance(), ALU.KEY_ALU_RESULT_31_0, 
					ALUOut.getInstance(), ALUOut.KEY_ALU_RESULT_LO);
			showRoute(ALU.getInstance(), ALU.KEY_ALU_RESULT_63_32, 
					ALUOut.getInstance(), ALUOut.KEY_ALU_RESULT_HI);
			
			switch (signals.get(Control.KEY_ALU_OP)){
			case 0:
				if (verbose) GUIOutput.println("Control : ALUop = " + signals.get(Control.KEY_ALU_OP) + " add");
				break;
			case 1:
				if (verbose) GUIOutput.println("Control : ALUop = " + signals.get(Control.KEY_ALU_OP) + " minus");
				break;
			case 2:
				if (verbose) GUIOutput.println("Control : ALUop = " + signals.get(Control.KEY_ALU_OP) + " and");
				break;
			case 3:
				if (verbose) GUIOutput.println("Control : ALUop = " + signals.get(Control.KEY_ALU_OP) + " or");
				break;
			case 4:
				if (verbose) GUIOutput.println("Control : ALUop = " + signals.get(Control.KEY_ALU_OP) + " multiply");
				break;
			}
		}

		//ALuSrcA被激活
		switch(signals.get(Control.KEY_ALU_SRC_A)){
		case 0:
			showRoute(Control.getInstance(), Control.KEY_ALU_SRC_A,
					MuxA.getInstance(), MuxA.KEY_ALU_SRCA);
			showRoute(PC.getInstance(), PC.KEY_PC_OUT,
					MuxA.getInstance(), MuxA.KEY_PC);
			if (verbose) GUIOutput.println("Control : ALUSrcA = 0 (PC)");
			break;
		case 1:
			showRoute(Control.getInstance(), Control.KEY_ALU_SRC_A,
					MuxA.getInstance(), MuxA.KEY_ALU_SRCA);
			showRoute(RegisterA.getInstance(), RegisterA.KEY_REGA_OUT,
					MuxA.getInstance(), MuxA.KEY_REGA);
			if (verbose) GUIOutput.println("Control : ALUSrcA = 1 (RegA)");
			break;
		}	
		
		//ALUSrcB被激活
		switch (signals.get(Control.KEY_ALU_SRC_B)){
		case 0:
			showRoute(Control.getInstance(), Control.KEY_ALU_SRC_B,
					MuxB.getInstance(), MuxB.KEY_ALU_SRCB);
			showRoute(RegBShifter.getInstance(), RegBShifter.KEY_RESULT,
					MuxB.getInstance(), MuxB.KEY_REGB_SHIFTED);
			if (verbose) GUIOutput.println("Control : ALUSrcB = 0 (RegB shifted)");
			break;
		case 1:
			showRoute(Control.getInstance(), Control.KEY_ALU_SRC_B,
					MuxB.getInstance(), MuxB.KEY_ALU_SRCB);
			if (verbose) GUIOutput.println("Control : ALUSrcB = 1 (4)");
			break;
		case 2:
			showRoute(Control.getInstance(), Control.KEY_ALU_SRC_B,
					MuxB.getInstance(), MuxB.KEY_ALU_SRCB);
			showRoute(ImmShifter.getInstance(), ImmShifter.KEY_RESULT,
					MuxB.getInstance(), MuxB.KEY_IMM_SHIFTED);
			if (verbose) GUIOutput.println("Control : ALUSrcB = 2 (imm9 << imm5)");
			break;
		case 3:
			showRoute(Control.getInstance(), Control.KEY_ALU_SRC_B,
					MuxB.getInstance(), MuxB.KEY_ALU_SRCB);
			showRoute(MuxImm2Ex.getInstance(), MuxImm2Ex.KEY_SELECTED,
					MuxB.getInstance(), MuxB.KEY_IMM_EXTENDED);
			if (verbose) GUIOutput.println("Control : ALUSrcB = 3 (imm extended)");
			break;
		case 4:
			showRoute(Control.getInstance(), Control.KEY_ALU_SRC_B,
					MuxB.getInstance(), MuxB.KEY_ALU_SRCB);
			showRoute(RegisterB.getInstance(), RegisterB.KEY_REGB_OUT,
					MuxB.getInstance(), MuxB.KEY_REGB_ORIG);
			if (verbose) GUIOutput.println("Control : ALUSrcB = 4 (RegB origin)");
			break;			
		}
		
		//寄存器写被激活
		switch(signals.get(Control.KEY_REG_WRITE)){
		case 1:
			showRoute(Control.getInstance(),Control.KEY_REG_WRITE,
					RegisterFile.getInstance(), RegisterFile.KEY_WRITE_ENABLE);
			showRoute(Mux2WR1.getInstance(), Mux2WR1.KEY_SELECTED,
					RegisterFile.getInstance(), RegisterFile.KEY_WRITE_REG1);
			showRoute(Mux2WD1.getInstance(), Mux2WD1.KEY_SELECTED,
					RegisterFile.getInstance(), RegisterFile.KEY_WRITE_DATA1);
			if (verbose) GUIOutput.println("Control : RegWrite !");
			break;
		case 2:
			showRoute(Control.getInstance(),Control.KEY_REG_WRITE,
					RegisterFile.getInstance(), RegisterFile.KEY_WRITE_ENABLE);
			showRoute(Mux2WR1.getInstance(), Mux2WR1.KEY_SELECTED,
					RegisterFile.getInstance(), RegisterFile.KEY_WRITE_REG1);
			showRoute(Mux2WD1.getInstance(), Mux2WD1.KEY_SELECTED,
					RegisterFile.getInstance(), RegisterFile.KEY_WRITE_DATA1);
			showRoute(InstructionRegister.getInstance(), InstructionRegister.KEY_INSTRUCTION_13_9,
					RegisterFile.getInstance(), RegisterFile.KEY_WRITE_REG2);
			showRoute(ALUOut.getInstance(), ALUOut.KEY_ALU_OUT_HI,
					RegisterFile.getInstance(), RegisterFile.KEY_WRITE_DATA2);
			if (verbose) GUIOutput.println("Control : RegWrite, wirte 2 registers !");
			break;
		}
		
		//RegDst被激活
		switch(signals.get(Control.KEY_REG_DST)){
		case 0:
			showRoute(Control.getInstance(), Control.KEY_REG_DST,
					Mux2WR1.getInstance(), Mux2WR1.KEY_REG_DST);
			showRoute(InstructionRegister.getInstance(), InstructionRegister.KEY_INSTRUCTION_4_0,
					Mux2WR1.getInstance(), Mux2WR1.KEY_RS2);
			if (verbose) GUIOutput.println("Control : RegDst = 0 (rs2)");
			break;
		case 1:
			showRoute(Control.getInstance(), Control.KEY_REG_DST,
					Mux2WR1.getInstance(), Mux2WR1.KEY_REG_DST);
			showRoute(InstructionRegister.getInstance(), InstructionRegister.KEY_INSTRUCTION_18_14,
					Mux2WR1.getInstance(), Mux2WR1.KEY_RD1);
			if (verbose) GUIOutput.println("Control : RegDst = 1 (rd1)");
			break;
		case 2:
			showRoute(Control.getInstance(), Control.KEY_REG_DST,
					Mux2WR1.getInstance(), Mux2WR1.KEY_REG_DST);
			outputAction(Mux2WR1.getInstance(), "选中立即数30");
			if (verbose) GUIOutput.println("Control : RegDst = 2 (30)");
			break;
		}
		
		//ImmSrc信号被激活
		switch(signals.get(Control.KEY_IMM_SRC)){
		case 1:
			showRoute(Control.getInstance(), Control.KEY_IMM_SRC,
					MuxImm2Ex.getInstance(), MuxImm2Ex.KEY_IMM_SRC);
			showRoute(InstructionRegister.getInstance(), InstructionRegister.KEY_INSTRUCTION_23_0,
					MuxImm2Ex.getInstance(), MuxImm2Ex.KEY_IMM24);
			if (verbose) GUIOutput.println("Control : ImmSrc = 0 (imm14)");
			break;
		case 0:
			showRoute(Control.getInstance(), Control.KEY_IMM_SRC,
					MuxImm2Ex.getInstance(), MuxImm2Ex.KEY_IMM_SRC);
			showRoute(InstructionRegister.getInstance(), InstructionRegister.KEY_INSTRUCTION_13_0,
					MuxImm2Ex.getInstance(), MuxImm2Ex.KEY_IMM14);
			if (verbose) GUIOutput.println("Control : ImmSrc = 1 (imm24)");
			break;
		}
		
		//PCRegister写被激活
		if (signals.get(Control.KEY_PCREG_WRITE) != 0){
			showRoute(Control.getInstance(), Control.KEY_PCREG_WRITE,
					PCRegister.getInstance(), PCRegister.KEY_PCREG_WRITE);
			showRoute(PC.getInstance(), PC.KEY_PC_OUT,
					PCRegister.getInstance(), PCRegister.KEY_PCREG_IN);
			if (verbose) GUIOutput.println("Control : PCRegWrite!");
		}
		
		//PC的写使能被激活
		if (OrGate.getInstance().getData(OrGate.KEY_RESULT) == 1){
			showRoute(OrGate.getInstance(), OrGate.KEY_RESULT,
					PC.getInstance(), PC.KEY_PC_WRITE_ENABLE);
			if (verbose) GUIOutput.println("Control : PCWrite !");
		}
		
		outputAll();
		return;
	}
	
	void showRoute(Component cfrom, int ifrom, Component cto, int ito){
		OutputRecord o = new OutputRecord(cfrom, ifrom, cto, ito);
		outputSet.add(o);
	}
	
	void outputAction(Component c, String description){
		System.out.println(c.getClass().getName() + description);
	}
	
	void outputAll(){
		
		GUIOutput.clearBusOutput();
		for (int i = 0; i < 24; i ++){
			for (OutputRecord o : outputSet){
				String name = o.cfrom.getClass().getName();
				if (name.substring(name.lastIndexOf(".")+1).equals(componentOrder.get(i))){
					
					//graph output
					GUIOutput.addBusOutput(o.cfrom, o.ifrom, o.cto, o.ito);					
					
					//text output					
					if (o.cfrom.getClass().getName().endsWith("Control"))
						continue;	
														
					String cf = o.cfrom.getClass().getName();
					cf = cf.substring(cf.lastIndexOf(".")+1, cf.length());
					String ct = o.cto.getClass().getName();
					ct = ct.substring(ct.lastIndexOf(".")+1, ct.length());
					int data = o.cfrom.getData(o.ifrom);
					
					if (ct.equals("FlagRegister")){
						switch(o.ito){
						case FlagRegister.FLAG_C:
							if (verbose) GUIOutput.println("Flag C = " + ALU.getInstance().getData(ALU.KEY_C));
							break;
						case FlagRegister.FLAG_N:
							if (verbose) GUIOutput.println("Flag N = " + ALU.getInstance().getData(ALU.KEY_N));
							break;
						case FlagRegister.FLAG_V:
							if (verbose) GUIOutput.println("Flag V = " + ALU.getInstance().getData(ALU.KEY_V));
							break;
						case FlagRegister.FLAG_Z:
							if (verbose) GUIOutput.println("Flag Z = " + ALU.getInstance().getData(ALU.KEY_Z));
							break;
						}						
						continue;
					}
					
					if (cf.equals("InstructionRegister")){
						if (o.ifrom == InstructionRegister.KEY_INSTRUCTION_31_24)
							cf = new String("IR (operation)");
						else if (o.ifrom == InstructionRegister.KEY_INSTRUCTION_8_5)
							cf = new String("IR (function)");
						else 
							cf = new String("IR");
					}					
					if (ct.equals("InstructionRegister"))
						ct = new String("IR");					
					if (cf.equals("ALU")){
						if (o.ifrom == ALU.KEY_ALU_RESULT_31_0)
							cf = new String("ALU low");
						else cf = new String("ALU high");
					}				
					if (ct.equals("ALUOut")){
						if (o.ito == ALUOut.KEY_ALU_RESULT_LO)
							ct = new String("ALUOut low");
						else ct = new String("ALUOut high");
					}
					if (cf.equals("ALUOut")){
						if (o.ifrom == ALUOut.KEY_ALU_OUT_LO)
							cf = new String("ALUOut low");
						else cf = new String("ALUOut high");
					}
					
					if (verbose) GUIOutput.println(cf + " => " + ct + " : " + data);
					
					if (ct.equals("RegisterFile") && o.ito == RegisterFile.KEY_WRITE_DATA1){
						GUIOutput.println("寄存器写入 : r[" + 
								Mux2WR1.getInstance().getData(Mux2WR1.KEY_SELECTED) 
								+ "] = " + data);						
					}
					if (ct.equals("RegisterFile") && o.ito == RegisterFile.KEY_WRITE_DATA2){
						GUIOutput.println("寄存器写入 : r[" + 
								InstructionRegister.getInstance().getData(InstructionRegister.KEY_INSTRUCTION_13_9)
								+ "] = " + data);
					}
					if (ct.equals("Memory") && o.ito == Memory.KEY_WRITE_DATA){
						if (Control.getInstance().getData(Control.KEY_MEM_WRITE) == 1)
							GUIOutput.println("存储器在" + MuxPC2M.getInstance().getData(MuxPC2M.KEY_SELECTED)+
									"写入字节" + data);
						if (Control.getInstance().getData(Control.KEY_MEM_WRITE) == 2)
							GUIOutput.println("存储器在" + MuxPC2M.getInstance().getData(MuxPC2M.KEY_SELECTED)+ 
									"写入字" + data);
					}
					if (ct.equals("PC") && o.ito == PC.KEY_PC_IN){
						GUIOutput.println("PC被写入地址" + data);
					}
				}
			}
		}
		return;
	}
	
	public void setVerbose(boolean flag){
		verbose = flag;
	}
	
}

class OutputRecord{
	
	Component cfrom;
	int ifrom;
	Component cto;
	int ito;
	
	OutputRecord(Component _cfrom, int _ifrom, Component _cto, int _ito){
		cfrom = _cfrom;
		ifrom = _ifrom;
		cto = _cto;
		ito = _ito;
	}
	
	@Override
	public int hashCode() {
		return 0;
	}
	
	@Override
	public boolean equals(Object oj){
		OutputRecord o = (OutputRecord)oj;
		return (cfrom == o.cfrom && ifrom == o.ifrom && cto == o.cto && ito == o.ito);
	}
	
	@Override
	public String toString() {
		return "("+cfrom.getClass().getName()+"."+ifrom+"=>"+cto.getClass().getName()+"."+ito+")";
	}
}